{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# [飞桨高层API使用指南](https://www.paddlepaddle.org.cn/documentation/docs/zh/practices/quick_start/high_level_api.html)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/lib/python3/dist-packages/urllib3/util/selectors.py:14: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3, and in 3.10 it will stop working\n",
      "  from collections import namedtuple, Mapping\n",
      "/usr/lib/python3/dist-packages/urllib3/_collections.py:2: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3, and in 3.10 it will stop working\n",
      "  from collections import Mapping, MutableMapping\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'2.1.0'"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import paddle\n",
    "import paddle.vision as vision\n",
    "import paddle.text as text\n",
    "\n",
    "paddle.__version__\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "视觉相关数据集： ['DatasetFolder', 'ImageFolder', 'MNIST', 'FashionMNIST', 'Flowers', 'Cifar10', 'Cifar100', 'VOC2012']\n",
      "自然语言相关数据集： ['Conll05st', 'Imdb', 'Imikolov', 'Movielens', 'UCIHousing', 'WMT14', 'WMT16']\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.8/dist-packages/ipykernel/ipkernel.py:283: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.\n",
      "  and should_run_async(code)\n"
     ]
    }
   ],
   "source": [
    "print(\"视觉相关数据集：\", paddle.vision.datasets.__all__)\n",
    "print(\"自然语言相关数据集：\", paddle.text.__all__)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "from paddle.vision.transforms import ToTensor\n",
    "\n",
    "# 训练数据集\n",
    "train_dataset = vision.datasets.MNIST(mode=\"train\", transform=ToTensor())\n",
    "\n",
    "# 验证数据集\n",
    "val_dataset = vision.datasets.MNIST(mode=\"test\", transform=ToTensor())\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "=============train dataset=============\n",
      "traindata1 label1\n",
      "traindata2 label2\n",
      "traindata3 label3\n",
      "traindata4 label4\n",
      "=============evaluation dataset=============\n",
      "testdata1 label1\n",
      "testdata2 label2\n",
      "testdata3 label3\n",
      "testdata4 label4\n"
     ]
    }
   ],
   "source": [
    "from paddle.io import Dataset\n",
    "\n",
    "\n",
    "class MyDataset(Dataset):\n",
    "    \"\"\"\n",
    "    步骤一：继承paddle.io.Dataset类\n",
    "    \"\"\"\n",
    "\n",
    "    def __init__(self, mode=\"train\"):\n",
    "        \"\"\"\n",
    "        步骤二：实现构造函数，定义数据读取方式，划分训练和测试数据集\n",
    "        \"\"\"\n",
    "        super().__init__()\n",
    "\n",
    "        if mode == \"train\":\n",
    "            self.data = [\n",
    "                [\"traindata1\", \"label1\"],\n",
    "                [\"traindata2\", \"label2\"],\n",
    "                [\"traindata3\", \"label3\"],\n",
    "                [\"traindata4\", \"label4\"],\n",
    "            ]\n",
    "        else:\n",
    "            self.data = [\n",
    "                [\"testdata1\", \"label1\"],\n",
    "                [\"testdata2\", \"label2\"],\n",
    "                [\"testdata3\", \"label3\"],\n",
    "                [\"testdata4\", \"label4\"],\n",
    "            ]\n",
    "\n",
    "    def __getitem__(self, index):\n",
    "        \"\"\"\n",
    "        步骤三：实现__getitem__方法，定义指定index时如何获取数据，并返回单条数据（训练数据，对应的标签）\n",
    "        \"\"\"\n",
    "        data = self.data[index][0]\n",
    "        label = self.data[index][1]\n",
    "\n",
    "        return data, label\n",
    "\n",
    "    def __len__(self):\n",
    "        \"\"\"\n",
    "        步骤四：实现__len__方法，返回数据集总数目\n",
    "        \"\"\"\n",
    "        return len(self.data)\n",
    "\n",
    "\n",
    "# 测试定义的数据集\n",
    "train_dataset_2 = MyDataset(mode=\"train\")\n",
    "val_dataset_2 = MyDataset(mode=\"test\")\n",
    "\n",
    "print(\"=============train dataset=============\")\n",
    "for data, label in train_dataset_2:\n",
    "    print(data, label)\n",
    "\n",
    "print(\"=============evaluation dataset=============\")\n",
    "for data, label in val_dataset_2:\n",
    "    print(data, label)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "from paddle.vision.transforms import Compose, Resize, ColorJitter\n",
    "\n",
    "# 定义想要使用那些数据增强方式，这里用到了随机调整亮度、对比度和饱和度，改变图片大小\n",
    "transform = Compose([ColorJitter(), Resize(size=100)])\n",
    "\n",
    "# 通过transform参数传递定义好的数据增项方法即可完成对自带数据集的应用\n",
    "train_dataset_3 = vision.datasets.MNIST(mode=\"train\", transform=transform)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "from paddle.io import Dataset\n",
    "\n",
    "\n",
    "class MyDataset(Dataset):\n",
    "    def __init__(self, mode=\"train\"):\n",
    "        super().__init__()\n",
    "\n",
    "        if mode == \"train\":\n",
    "            self.data = [\n",
    "                [\"traindata1\", \"label1\"],\n",
    "                [\"traindata2\", \"label2\"],\n",
    "                [\"traindata3\", \"label3\"],\n",
    "                [\"traindata4\", \"label4\"],\n",
    "            ]\n",
    "        else:\n",
    "            self.data = [\n",
    "                [\"testdata1\", \"label1\"],\n",
    "                [\"testdata2\", \"label2\"],\n",
    "                [\"testdata3\", \"label3\"],\n",
    "                [\"testdata4\", \"label4\"],\n",
    "            ]\n",
    "\n",
    "        # 定义要使用的数据预处理方法，针对图片的操作\n",
    "        self.transform = Compose([ColorJitter(), Resize(size=100)])\n",
    "\n",
    "    def __getitem__(self, index):\n",
    "        data = self.data[index][0]\n",
    "\n",
    "        # 在这里对训练数据进行应用\n",
    "        # 这里只是一个示例，测试时需要将数据集更换为图片数据进行测试\n",
    "        data = self.transform(data)\n",
    "\n",
    "        label = self.data[index][1]\n",
    "\n",
    "        return data, label\n",
    "\n",
    "    def __len__(self):\n",
    "        return len(self.data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Sequential形式组网\n",
    "mnist = paddle.nn.Sequential(\n",
    "    paddle.nn.Flatten(),\n",
    "    paddle.nn.Linear(784, 512),\n",
    "    paddle.nn.ReLU(),\n",
    "    paddle.nn.Dropout(0.2),\n",
    "    paddle.nn.Linear(512, 10),\n",
    ")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Layer类继承方式组网\n",
    "class Mnist(paddle.nn.Layer):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "\n",
    "        self.flatten = paddle.nn.Flatten()\n",
    "        self.linear_1 = paddle.nn.Linear(784, 512)\n",
    "        self.linear_2 = paddle.nn.Linear(512, 10)\n",
    "        self.relu = paddle.nn.ReLU()\n",
    "        self.dropout = paddle.nn.Dropout(0.2)\n",
    "\n",
    "    def forward(self, inputs):\n",
    "        y = self.flatten(inputs)\n",
    "        y = self.linear_1(y)\n",
    "        y = self.relu(y)\n",
    "        y = self.dropout(y)\n",
    "        y = self.linear_2(y)\n",
    "\n",
    "        return y\n",
    "\n",
    "\n",
    "mnist_2 = Mnist()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5.3 模型封装\n",
    "定义好网络结构之后来使用paddle.Model完成模型的封装，将网络结构组合成一个可快速使用高层API进行训练、评估和预测的类。\n",
    "\n",
    "在封装的时候有两种场景，动态图训练模式和静态图训练模式。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.8/dist-packages/paddle/fluid/framework.py:689: DeprecationWarning: `np.bool` is a deprecated alias for the builtin `bool`. To silence this warning, use `bool` by itself. Doing this will not modify any behavior and is safe. If you specifically wanted the numpy scalar type, use `np.bool_` here.\n",
      "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n",
      "  elif dtype == np.bool:\n"
     ]
    }
   ],
   "source": [
    "# 使用GPU训练\n",
    "# paddle.set_device('gpu')\n",
    "\n",
    "# 模型封装\n",
    "\n",
    "## 场景1：动态图模式\n",
    "## 1.1 为模型预测部署场景进行模型训练\n",
    "## 需要添加input和label数据描述，否则会导致使用model.save(training=False)保存的预测模型在使用时出错\n",
    "inputs = paddle.static.InputSpec([-1, 1, 28, 28], dtype=\"float32\", name=\"input\")\n",
    "label = paddle.static.InputSpec([-1, 1], dtype=\"int8\", name=\"label\")\n",
    "model = paddle.Model(mnist, inputs, label)\n",
    "\n",
    "## 1.2 面向实验而进行的模型训练\n",
    "## 可以不传递input和label信息\n",
    "# model = paddle.Model(mnist)\n",
    "\n",
    "## 场景2：静态图模式\n",
    "# paddle.enable_static()\n",
    "# paddle.set_device('gpu')\n",
    "# input = paddle.static.InputSpec([None, 1, 28, 28], dtype='float32')\n",
    "# label = paddle.static.InputSpec([None, 1], dtype='int8')\n",
    "# model = paddle.Model(mnist, input, label)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "---------------------------------------------------------------------------\n",
      " Layer (type)       Input Shape          Output Shape         Param #    \n",
      "===========================================================================\n",
      "   Flatten-1       [[1, 28, 28]]           [1, 784]              0       \n",
      "   Linear-1          [[1, 784]]            [1, 512]           401,920    \n",
      "    ReLU-1           [[1, 512]]            [1, 512]              0       \n",
      "   Dropout-1         [[1, 512]]            [1, 512]              0       \n",
      "   Linear-2          [[1, 512]]            [1, 10]             5,130     \n",
      "===========================================================================\n",
      "Total params: 407,050\n",
      "Trainable params: 407,050\n",
      "Non-trainable params: 0\n",
      "---------------------------------------------------------------------------\n",
      "Input size (MB): 0.00\n",
      "Forward/backward pass size (MB): 0.02\n",
      "Params size (MB): 1.55\n",
      "Estimated Total Size (MB): 1.57\n",
      "---------------------------------------------------------------------------\n",
      "\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'total_params': 407050, 'trainable_params': 407050}"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.summary((1, 28, 28))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 为模型训练做准备，设置优化器，损失函数和精度计算方式\n",
    "model.prepare(\n",
    "    paddle.optimizer.Adam(parameters=model.parameters()),\n",
    "    paddle.nn.CrossEntropyLoss(),\n",
    "    paddle.metric.Accuracy(),\n",
    ")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The loss value printed in the log is the current step, and the metric is the average value of previous steps.\n",
      "Epoch 1/5\n"
     ]
    },
    {
     "ename": "",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m在当前单元格或上一个单元格中执行代码时 Kernel 崩溃。\n",
      "\u001b[1;31m请查看单元格中的代码，以确定故障的可能原因。\n",
      "\u001b[1;31m单击<a href='https://aka.ms/vscodeJupyterKernelCrash'>此处</a>了解详细信息。\n",
      "\u001b[1;31m有关更多详细信息，请查看 Jupyter <a href='command:jupyter.viewOutput'>log</a>。"
     ]
    }
   ],
   "source": [
    "# 启动模型训练，指定训练数据集，设置训练轮次，设置每次数据集计算的批次大小，设置日志格式\n",
    "model.fit(train_dataset, epochs=5, batch_size=64, verbose=1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
